package com.dog.modules.websocket.config.Interceptor;

import cn.hutool.http.HttpUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.dog.framework.core.constant.TokenConstants;
import com.dog.framework.core.utils.DateUtils;
import com.dog.framework.core.constant.CleaningRedisKeyPrefixConst;
import com.dog.modules.websocket.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import java.nio.charset.Charset;
import java.util.Date;
import java.util.Map;

/**
 * Websocket握手认证
 *
 * @author lee
 * @date 2023/04/06
 */
@Slf4j
@Component
public class AuthenticationInterceptor implements HandshakeInterceptor {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 握手前
     *
     * @param request
     * @param response
     * @param wsHandler
     * @param attributes
     * @return
     * @throws Exception
     */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        String path = request.getURI().getPath();
        // 获得请求参数
        Map<String, String> paramMap = HttpUtil.decodeParamMap(request.getURI().getQuery(), Charset.forName("utf-8"));
        // 从 http 请求头中取出 token
        String reqToken = paramMap.get(Constants.PARAM_KEY_TOKEN);

        if (StringUtils.isEmpty(reqToken)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.error("Unauthorized");
            return false;
        }
        Long userId = 1001L;
        String userName = "liuxiangke0210";
        String password = "BB0FCBAF0B7B7D3B09B7C50BAE4BDD40";
        //验证redis中的token
        String redisToken = null;
        if (path.startsWith("/op")) {
            String user = "liuxk";
            try {
                String mobile = JWT.decode(reqToken).getClaim(TokenConstants.TOKEN_CLAIM_MOBILE).asString();
                // user = userApi.queryByMobile(mobile);
            } catch (Exception e) {
                e.printStackTrace();
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                log.error("Authentication failed");
                return false;
            }
            if (user == null) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                log.error("Authentication failed");
                return false;
            }

            redisToken = redisTemplate.opsForValue().get(String.format(CleaningRedisKeyPrefixConst.OP_USER_TOKEN, userId));
            redisToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtb2JpbGUiOiIxNTIyMTYxODczOSIsInVzZXJOYW1lIjoibGl1eGsiLCJleHAiOjE3MDM2NzE5OTJ9.oT29ruyqNgiFQazlqOPl1UbHLIFAHH0mx8mGrsX7jw8";
        } else if (path.startsWith("/biz")) {
            // todo  验证模块
        } else {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.error("Unauthorized: {}", path);
            return false;
        }
        if (StringUtils.isBlank(redisToken) || !reqToken.equals(redisToken)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.error("Unauthorized: token error");
            log.error("request token: {}", reqToken);
            log.error("token: {}", redisToken);
            return false;
        }
        // 验证 token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(password)).build();
        try {
            // 验证签名
            DecodedJWT jwt = jwtVerifier.verify(reqToken);
            // 验证过期时间
            Date expDate = jwt.getExpiresAt();
            if (DateUtils.compareDateTime(expDate, new Date()) < 0) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                log.error("Unauthorized: token expired");
                return false;
            }
        } catch (JWTVerificationException e) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            log.error("Unauthorized: token error");
            return false;
        }

        attributes.put(Constants.PARAM_KEY_TOKEN, reqToken);
        attributes.put(Constants.PARAM_KEY_USER_ID, userId);
        attributes.put(Constants.PARAM_KEY_USER_NAME, userName);
        return true;
    }

    /**
     * 握手后
     *
     * @param request
     * @param response
     * @param wsHandler
     * @param exception
     */
    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        log.debug("url{}握手完成", request.getURI().getPath());
    }

}
